<?php

namespace km\graphics;

class RasterImageBackendGD implements RasterImageBackend {
	private $filename;
	/**
	 * @var resource
	 */
	private $handler;
	/**
	 * (non-PHPdoc)
	 * @see lib/km/graphics/RasterImageBackend#loadFile($filename)
	 */
	function loadFile($filename)
	{
		$this->filename = $filename;
		$this->loadResource($this->createImageHandler($filename));
	}
	/**
	 * @return int
	 */
	function getWidth()
	{
		return imagesx($this->handler);
	}
	/**
	 * @return int
	 */
	function getHeight()
	{
		return imagesy($this->handler);
	}
	/**
	 * Load a imagecreate() or a similar function result
	 * @param resource $image_handler
	 * @return void
	 */
	function loadResource($image_handler)
	{
		if (! $image_handler)
		{
			throw new GraphicsException('loadResource: Image handler evaluates to FALSE');
		}
		$this->handler = $this->savealpha($image_handler);
	}
	/**
	 * (non-PHPdoc)
	 * @see lib/km/graphics/RasterImageBackend#copy($dst_x, $dst_y, $src_x, $src_y, $dst_width, $dst_height, $src_width, $src_height)
	 */
	function region($x, $y, $width, $height, $new_width = null, $new_height = null)
	{
		$new_width	= $new_width ?: $width;
		$new_height	= $new_height ?: $height;
		$dst		= $this->savealpha(imagecreatetruecolor($new_width, $new_height));
		if (! imagecopyresampled($dst, $this->handler, 0, 0, $x, $y, $new_width, $new_height, $width, $height))
		{
			throw new GraphicsException('copy: Failed to copy image');
		}
		
		$this->handler = $dst;
		
		return true;
	}
	/**
	 * (non-PHPdoc)
	 * @see lib/km/graphics/RasterImageBackend#reset($width, $height, $r, $g, $b, $alpha)
	 */
	function reset($width, $height, $r = 255, $g = 255, $b = 255, $alpha = 0)
	{
		$this->handler = imagecreatetruecolor($width, $height);
		$this->savealpha($this->handler);
		imagefill($this->handler, 0, 0, imagecolorallocatealpha($this->handler, $r, $g, $b, $alpha));
	}
	/**
	 * $image argument may be a image resource, image string (file contents),  
	 * a RasterImageBackendGD instance or a RasterImage instance holding
	 * a RasterImageBackendGD instance as backend
	 * (non-PHPdoc)
	 * @see lib/km/graphics/RasterImageBackend#paste($image, $x, $y)
	 * @throws GraphicsException
	 */
	function paste($image, $x = 0, $y = 0)
	{
		if (is_resource($image)) {
			return $this->pasteResource($image, $x, $y);
		} elseif (is_string($image)) {
			return $this->pasteResource(imagecreatefromstring($image), $x, $y);
		} elseif ($image instanceof RasterImageBackendGD) {
			return $this->pasteResource($image->getHandler(), $x, $y);
		} elseif (($image instanceof RasterImage) && 
			($backend = $image->getBackend()) && 
			($backend instanceof RasterImageBackendGD)) {
			return $this->pasteResource($backend->getHandler(), $x, $y);
		} else {
			throw new GraphicsException(__METHOD__ . ' expects 1st aegument to be a image resource, image string' . 
			', a RasterImageBackendGD instance or a RasterImage instance holding a RasterImageBackendGD instance as backend');
		}
	}
	function getHandler()
	{
		return $this->handler;
	}
	private function pasteResource($r, $x, $y)
	{
		$width = imagesx($r);
		$height = imagesy($r);
		$this->savealpha($r);
		$transparent = imagecolorallocatealpha($r, 255, 255, 255, 127);
		imagefilledrectangle($r, 0, 0, $width, $height, $transparent);
		imagecopyresampled($this->handler, $r, $x, $y, 0, 0, $width, $height, $width, $height);
	}
	/**
	 * Load image as string
	 * @param string $image_string
	 * @return void
	 */
	function loadString($image_string)
	{
		$this->loadResource(@imagecreatefromstring($image_string));
	}
	
	function saveFile($filename)
	{
		return $this->doSave($filename);
	}
	function saveString($type)
	{
		return $this->doSave(null, $type);
	}
	function doSave($filename, $type = null)
	{
		if ((null === $type) && 
			(! $type = strtolower(pathinfo($filename, PATHINFO_EXTENSION)))) {
			
			throw new GraphicsException('Cannot determine resulting image type');
			
		}
		
		switch ($type)
		{
			case 'jpg':
			case 'jpeg':
				$callback = 'imagejpeg';
				break;
			case 'png':
				$callback = 'imagepng';
				break;
			case 'gif':
				$callback = 'imagegif';
				break;
			case 'bmp':
				$callback = 'imagewbmp';
				break;
			default:
				throw new GraphicsException('Unsupported image type ' . $ext);
				break;
		}
		
		ob_start();
		$result = call_user_func_array($callback, array($this->handler, $filename));
		$buffer = ob_get_clean();
		
		if (! $result)
		{
			throw new GraphicsException('Failed to save image: ' . $buffer);
		}
		
		return $buffer;
	}
	
	private function createImageHandler($filename)
	{
		list($w, $h, $type) = getimagesize($filename);
		switch ($type)
		{
			case IMAGETYPE_JPEG:
			case IMAGETYPE_JPEG2000:
				$ret = imagecreatefromjpeg($filename);
				break;
			case IMAGETYPE_GIF:
				$ret = imagecreatefromgif($filename);
				break;
			case IMAGETYPE_PNG:
				$ret = imagecreatefrompng($filename);
				break;
			default:
				throw new GraphicsException('Unsupported file type');
				break;
		}
		return $ret;
	}
	
	private function savealpha($h)
	{
		imagesavealpha($h, true);
		imagealphablending($h, true);
		return $h;
	}
}